#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<hs/hs.h>

// 函数声明
// 匹配回调函数
static int on_match(unsigned int id, unsigned long long from,
        unsigned long long to, unsigned int flags, void *ctx);
int judge_poker(const char *in_hand, const char *op_type);

// 测试/驱动
int main()
{
    int i;
    char *in[] = {"12233445566677", "12233445566677", "12233445566677",
                  "12233445566677", "12233445566677", "12233445566677",
                  "12233445566677", "12233445566677", "12233445566677",
                  "66666666666666", "22222222222222", "12356789",
                  "1111111111123456789"};
    char *op[] = {"33", "8", "444", "88", "6", "777", "12345",
                  "45678", "1111", "12345", "12345", "12345", "12345"};

    for(i = 0; i < sizeof(in) / sizeof(in[0]); i++)
    {
        if(judge_poker(in[i], op[i]))
        {
            puts("YES");
        }
        else
        {
            puts("NO");
        }
    }

    return 0;
}

int judge_poker(const char *in_hand, const char *op_type)
{
    // 正则表达式查找表
    const char *re_pat[] = {
      "(2{1})|(3{1})|(4{1})|(5{1})|(6{1})|(7{1})|(8{1})|(9{1})", // 2--9
      "(2{2})|(3{2})|(4{2})|(5{2})|(6{2})|(7{2})|(8{2})|(9{2})", // 22等
      "(2{3})|(3{3})|(4{3})|(5{3})|(6{3})|(7{3})|(8{3})|(9{3})", // 222等
      "(2{4})|(3{4})|(4{4})|(5{4})|(6{4})|(7{4})|(8{4})|(9{4})", // 2222等
      "(2+3+4+5+6)|" // 23456
      "(3+4+5+6+7)|" // 34567
      "(4+5+6+7+8)|" // 45678
      "(5+6+7+8+9)"  // 56789
    };

    const char *pat;

    int flag;
    size_t in_len = strlen(in_hand);
    size_t op_len = strlen(op_type);
    size_t off_ratio;

    // 根据对手牌长度确定正则表达式字符串偏移量系数
    off_ratio = op_len == 5 ? 12 : 7;

    // 根据对手牌型取得正则表达式字符串
    pat = re_pat[op_len - 1] + (op_type[0] - '0' - 1) * off_ratio;

    // 正则对象指针
    hs_database_t *db = NULL;
    hs_compile_error_t *compile_err = NULL;

    // 编译正则表达式
    if(hs_compile(pat, HS_FLAG_DOTALL, HS_MODE_BLOCK, NULL,
                  &db, &compile_err) != HS_SUCCESS)
    {
        fprintf(stderr, "ERROR: Unable to compile pattern \"%s\": %s\n",
                pat, compile_err->message);
        hs_free_compile_error(compile_err);
        exit(EXIT_FAILURE);
    }

    // 申请临时空间
    hs_scratch_t *scratch = NULL;
    if(hs_alloc_scratch(db, &scratch) != HS_SUCCESS)
    {
        fprintf(stderr, "ERROR: Unable to allocate scratch space."
                        " Exiting.\n");
        hs_free_database(db);
        exit(EXIT_FAILURE);
    }

    flag = 0;

    // 正则匹配
    if(hs_scan(db, in_hand, in_len, 0, scratch, on_match, &flag)
            != HS_SUCCESS)
    {
        fprintf(stderr, "ERROR: Unable to scan input buffer. Exiting.\n");
        hs_free_scratch(scratch);
        hs_free_database(db);
        exit(EXIT_FAILURE);
    }

    // 释放空间
    hs_free_scratch(scratch);
    hs_free_database(db);

    // 返回结果
    return flag;
}

static int on_match(unsigned int id, unsigned long long from,
        unsigned long long to, unsigned int flags, void *ctx)
{
    int *flag = (int *)ctx;

    *flag = 1;

    return 0; // 返回0继续匹配，返回1结束匹配
}
